/*****************************************************
 * Copyright ?, 2006-2008 Huawei Technologies Co.,Ltd. 
 * Filename: surf.cpp
 * Version: 1.0 / Author: Lei Yu / Date: 2007-4-27
 * Description: 
 * Version: 
 * Function List :
 * History:
 * leiyu    2007-4-27   1.0  create this file
 ****************************************************/

#include "precomp.h"

extern DISPLAY_ARGS gHisiArgs[1];

/*****************************************************
 * Function: FlipInProgress
 * Description: whether display is in flip
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: NONE
 * Output: NONE
 * Return: not supported by hardware, return FALSE
 * Others: NONE
 ****************************************************/
int HisiDisp::FlipInProgress(void)
{
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("HisiDisp::FlipInProgress\r\n")));

    return FALSE;
}

/*****************************************************
 * Function: SurfaceBusyFlipping
 * Description: whether display is busy flipping
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: GPESurf *pSurf: point to GPE surface
 * Output: NONE
 * Return: not supported by hardware, return FALSE
 * Others: NONE
 ****************************************************/
int HisiDisp::SurfaceBusyFlipping(GPESurf*) 
{
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("HisiDisp::SurfaceBusyFlipping\r\n")));
    
    return FALSE;
}

/*****************************************************
 * Function: SetPrimarySurface
 * Description: Display Primary Surface
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: GPESurf *pSurf: surface to display 
 *        BOOL bWaitForVBlank: flag to judge whether to
 *                             wait for vertical blank
 * Output: NONE
 * Return: NONE
 * Others: NONE
 ****************************************************/
void HisiDisp::SetPrimarySurface(GPESurf *pSurf, BOOL bWaitForVBlank)
{
#if 0
    DWORD   dwRegValue;
#endif
    HisiSurf *pTempSurf;
  
    WaitForNotBusy();

    if (bWaitForVBlank)
    {
        DEBUGMSG(GPE_ZONE_HISI, (TEXT("Do not need wait for vertical blank.\n")));
    }

#ifdef _CPPRTTI
    pTempSurf = dynamic_cast<HisiSurf *>(pSurf);
#else
    pTempSurf = (HisiSurf *)pSurf;  /*lint !e1774*/
#endif

    if (NULL == pTempSurf)
    {
        return;
    }

    _memwD_EDCreg(EDC_GRP_ADDR, pTempSurf->GetPhysicalAddress());

    if (!m_bSetPrimaySurface)
    {
        m_bSetPrimaySurface = 1;
#if 0
        _memwD_EDCreg(EDC_GRP_LN_OFFSET, pSurf->Stride() & GRP_LN_OFFSET_MASK);
        _memwD_EDCreg(EDC_GRP_XY, 0);
        dwRegValue = ((((DWORD)m_nScreenWidthSave - 1) << GRP_SIZE_HRZ_SHIFT) & GRP_SIZE_HRZ_MASK) |
                     ((((DWORD)m_nScreenHeightSave - 1) << GRP_SIZE_VRT_SHIFT) & GRP_SIZE_VRT_MASK);
        _memwD_EDCreg(EDC_GRP_SIZE, dwRegValue);
#if 0        
        dwRegValue = GRP_EN | GRP_TOP | GRP_ROT_0 |
                     GRP_RGBIN_RGB565;
#else
     dwRegValue = GRP_EN | GRP_ROT_0 |
                     GRP_RGBIN_RGB565;
#endif
        _memwD_EDCreg(EDC_GRP_CTL, dwRegValue);
#endif   
        /* Init CLCDC/SSP/SYSCTL */
        //DispInitialize();
        m_lcmCtrl->DispInitialize();
        
        // Advertise power class interface
        if (!AdvertiseInterface(&m_powerClassGUID, L"HiDisplayDriver", TRUE)) 
        {
            DEBUGMSG(GPE_ZONE_HISI, (TEXT("AdvertiseInterface Error!!!\r\n")));
        }

    }
    
     
    return;
}

SCODE HisiDisp::AllocFromReservedMem(DDGPESurf **ppSurf, int width, 
                                                int height, EGPEFormat format, 
                                                EDDGPEPixelFormat pixelFormat, 
                                                int surfaceFlags)
{
    DWORD bpp  = EGPEFormatToBpp[format];
    DWORD stride = (((bpp * (DWORD)width) + 31) >> 5) << 2;
    DWORD nSurfaceSize = stride * (DWORD)height;
    SurfaceHeap *pStack;

    *ppSurf = 0;
    
    if ((surfaceFlags & GPE_BACK_BUFFER) 
        || (surfaceFlags & GPE_REQUIRE_VIDEO_MEMORY) 
        || ((surfaceFlags & GPE_PREFER_VIDEO_MEMORY)
        && (format == m_pMode->format))
        )
    {
        /* Attempt to allocate from SRAM */
        DEBUGMSG(GPE_ZONE_HISI, (TEXT("Attempt to allocate from SRAM.\r\n")));

        pStack = m_pSramHeap->Alloc(nSurfaceSize);

        if (pStack)
        {

            DWORD offset = pStack->Address() - m_pSramBuffer;
             
            *ppSurf = new HisiSurf(width, height, offset, 
                                   (PBYTE)m_pSramBuffer + offset, 
                                   (int)stride, format, 
                                   pixelFormat, pStack);
            
            if (!(*ppSurf))
            {
                DISPMSG(1, (TEXT("SRAM new HisiSurf, but Not enough memory!\r\n")));
                pStack->Free();
                return E_OUTOFMEMORY;
            }
            else
            {
                /* logo in ipl, so we cann't clear frame buffer here */
                if (pStack->Address() != m_pSramBuffer)
                {
                    memset((void *)(pStack->Address()), 0, nSurfaceSize);
                }
                return S_OK;
            }
        }

        /* Attempt to allocate from Reserved SDRAM */  
        DEBUGMSG(GPE_ZONE_HISI, (TEXT("Attempt to allocate from Reserved SDRAM.\r\n")));
        
        pStack = m_pSdramHeap->Alloc(nSurfaceSize);
        
        if (pStack)
        {
            DWORD offset = pStack->Address() - m_pSdramBuffer;
            *ppSurf = new HisiSurf(width, height, offset, (PBYTE)m_pSdramBuffer + offset, (int)stride,
                                      format, pixelFormat, pStack);

            if (!(*ppSurf))
            {
                DISPMSG(1, (TEXT("Reserved Mem new HisiSurf, but Not enough memory!\r\n")));                
                pStack->Free();
                return E_OUTOFMEMORY;
            }
            
            memset((void *)(pStack->Address()), 0, nSurfaceSize);
            
            return S_OK;
        }
        
        if (surfaceFlags & GPE_REQUIRE_VIDEO_MEMORY)
        {
            DISPMSG(1, (TEXT("Not enough video memory!\r\n")));
            *ppSurf = 0;
            return E_OUTOFMEMORY;
        }
    }

    return E_INVALIDARG;
}

/*****************************************************
 * Function: AllocSurface
 * Description: alloc surface, defined by class GPE, 
 *              overloaded here
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: int width: width of surface
 *        int height: height of surface
 *        EGPEFormat format: GPE format of surface
 *        int surfaceFlags: where to alloc the surface,
 *                          video memory or system memory
 * Output: GPESurf *ppSurf: point to constructed surface object
 * Return: 
 * Others: NONE
 ****************************************************/

SCODE HisiDisp::AllocSurface(GPESurf **ppSurf, int width, 
                                int height, EGPEFormat format, 
                                int surfaceFlags)
{
    SCODE sc = AllocFromReservedMem((DDGPESurf**)ppSurf, 
                        width, 
                        height,
                        format, 
                        EGPEFormatToEDDGPEPixelFormat[format],
                        surfaceFlags);

    if (E_INVALIDARG == sc)
    {
        *ppSurf = new GPESurf(width, height, format);

        if (*ppSurf)
        {
            /* check we allocated bits succesfully */
            if (!((*ppSurf)->Buffer()))
            {
                DISPMSG(1, (TEXT("new GPESurf success, but Not enough memory!\r\n")));
                delete *ppSurf;
                *ppSurf = 0;
                return E_OUTOFMEMORY;
            }

            return S_OK;
        }

        DISPMSG(1, (TEXT("GPESurf: Not enough memory!\r\n")));

        return E_OUTOFMEMORY;
    }

    return sc;
}

/*****************************************************
 * Function: AllocSurface
 * Description: alloc surface, defined by class HisiDisp 
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: int width: width of surface
 *        int height: height of surface
 *        EGPEFormat format: GPE format of surface
 *        int surfaceFlags: where to alloc the surface,
 *                          video memory or system memory
 * Output: DDGPESurf *ppSurf: point to constructed surface object
 * Return: if there is not enough memory
 *         return E_NOT_ENOUGH_MEMORY
 *         success to alloc surface 
 *         return S_OK
 * Others: NONE
 ****************************************************/
SCODE HisiDisp::AllocSurface(DDGPESurf **ppSurf, int width, 
                                int height, EGPEFormat format, 
                                EDDGPEPixelFormat pixelFormat, 
                                int surfaceFlags)
{
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("HisiDisp::AllocSurface width %d height %d\r\n"), width, height));

    DWORD bpp  = EGPEFormatToBpp[format];
    DWORD stride = (((bpp * (DWORD)width) + 31) >> 5) << 2;

    SCODE sc = AllocFromReservedMem((DDGPESurf**)ppSurf, 
                        width, 
                        height,
                        format, 
                        EGPEFormatToEDDGPEPixelFormat[format],
                        surfaceFlags);
    
    if (E_INVALIDARG == sc)
    {
        /* Allocate from system memory */
        DEBUGMSG(GPE_ZONE_HISI, (TEXT("Creating a DDGPESurf in system memory -EGPEFormat = %d, DDGPEFormat = %d\r\n"),
                                    format, pixelFormat)); 
        *ppSurf = new DDGPESurf(width, height, (int)stride, format, pixelFormat);

    if (*ppSurf)
    {
        /* check we allocated bits succesfully */
        if (!((*ppSurf)->Buffer()))
        {
            DISPMSG(1, (TEXT("new DDGPESurf success, but Not enough memory!\r\n")));
            delete *ppSurf;
            *ppSurf = 0;
            return E_OUTOFMEMORY;
        }

        return S_OK;
    }

    DISPMSG(1, (TEXT("DDGPESurf: Not enough memory!\r\n")));

        return E_OUTOFMEMORY;
    }

    return sc;
}

/*****************************************************
 * Function: AllocSurface
 * Description: alloc video surface, defined by class HisiDisp 
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: int width: width of surface
 *        int height: height of surface
 *        int OverridePitch: mainly used by YV12
 *        int OverrideSize: mainly used by YV12
 *        EGPEFormat format: GPE format of surface
 *        EDDGPEPixelFormat pixelFormat: DDGPE format of surface
 * Output: DDGPESurf *ppSurf: point to constructed surface object
 * Return: if there is not enough memory
 *         return E_NOT_ENOUGH_MEMORY
 *         success to alloc surface 
 *         return S_OK
 * Others: NONE
 ****************************************************/
SCODE HisiDisp::AllocSurface(DDGPESurf **ppSurf, int width, int height, 
                            int OverridePitch, int OverrideSize, 
                            EGPEFormat format, EDDGPEPixelFormat pixelFormat)
{
    /* will be called for video memory only */
    DWORD bpp  = EGPEFormatToBpp[format];
    DWORD stride = ((bpp * (DWORD)width + 31) >> 5) << 2;
    DWORD nSurfaceSize = stride * (DWORD)height;
    SurfaceHeap *pStack;
    HisiSurf *pHisiSurf = 0;

    *ppSurf = 0;
    
    if (OverridePitch > 8) 
    {
        stride = OverridePitch;
    }

    /* Primary Surface is already allocated */
    if (OverridePitch == 0)   
    {
#ifdef _CPPRTTI
        *ppSurf = dynamic_cast<DDGPESurf *>(m_pPrimarySurface);
#else
        *ppSurf = (DDGPESurf *)m_pPrimarySurface;   /*lint !e1774*/
#endif
        return S_OK;
    }

    /* Attempt to allocate from SRAM */
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("Attempt to allocate from SRAM.\r\n")));

    pStack = m_pSramHeap->Alloc((OverrideSize != 0) ? 
                                (DWORD)OverrideSize : nSurfaceSize);
    if (pStack)
    {

        DWORD offset = pStack->Address() - m_pSramBuffer;
      
        pHisiSurf = new HisiSurf(width, height, offset, 
                                 (PBYTE)m_pSramBuffer + offset, 
                                 (int)stride, format, 
                                  pixelFormat, pStack);   

        if (0 == pHisiSurf)/*lint !e774*/
        {
            pStack->Free();
            return E_OUTOFMEMORY;
        }
     
        pHisiSurf->SetSurfaceSize((OverrideSize != 0) ? 
                                   OverrideSize : (int)nSurfaceSize);
        *ppSurf = pHisiSurf;
        
        if (pStack->Address() != m_pSramBuffer)
        {
            memset((void *)(pStack->Address()), 0, (OverrideSize!=0) ? OverrideSize : (int)nSurfaceSize);
        }
        
        return S_OK;
    }

    /* Attempt to allocate from Reserved SDRAM */  
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("Attempt to allocate from Reserved SDRAM.\r\n")));

    DEBUGMSG(GPE_ZONE_HISI, (TEXT("SRAM Available size: %d.\r\n"), m_pSramHeap->Available()));   
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("SDRAM Available size: %d.\r\n"), m_pSdramHeap->Available()));   
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("SRAM Total size: %d.\r\n"), m_pSramHeap->Size()));   
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("SDRAM Total size: %d.\r\n"), m_pSdramHeap->Size()));   

    pStack = m_pSdramHeap->Alloc((OverrideSize != 0) ? (DWORD)OverrideSize : nSurfaceSize);
    
    if (pStack)
    {
        DWORD offset = pStack->Address() - m_pSdramBuffer;
        pHisiSurf = new HisiSurf(width, height, offset, 
                                 (PBYTE)m_pSdramBuffer + offset, 
                                 (int)stride, format, 
                                 pixelFormat, pStack);

        if (0 == pHisiSurf)/*lint !e774*/
        {
            pStack->Free();
            return E_OUTOFMEMORY;
        }

        pHisiSurf->SetSurfaceSize((OverrideSize!=0) ? OverrideSize : (int)nSurfaceSize);
        *ppSurf = pHisiSurf;
        
        memset((void *)(pStack->Address()), 0, (OverrideSize!=0) ? OverrideSize : (int)nSurfaceSize);
        
        return S_OK;
    }

    *ppSurf = (DDGPESurf *)NULL;
    return E_OUTOFMEMORY;
}

/*****************************************************
 * Function: HisiSurf
 * Description: constructed funtion of class HisiSurf
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: DWORD offset: start address of surface offset to 
 *                      video memory
 *        PVOID pBits: start address of surface
 * Output: NONE
 * Return: NONE
 * Others: NONE
 ****************************************************/
HisiSurf::HisiSurf(int width, int height, DWORD offset, PVOID pBits, 
                 int stride, EGPEFormat format, EDDGPEPixelFormat pixelFormat,
                 SurfaceHeap *pHeap)
                : DDGPESurf(width, height, pBits, stride, format, pixelFormat)
{
    m_pSurfHeap = pHeap;
    m_fInVideoMemory = TRUE;
    m_nOffsetInVideoMemory = offset;
    m_ScreenHeight = height;
    m_ScreenWidth= width;
}

/*****************************************************
 * Function: ~HisiSurf
 * Description: deconstructed funtion of class HisiSurf
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: NONE
 * Output: NONE
 * Return: NONE
 * Others: NONE
 ****************************************************/
HisiSurf::~HisiSurf(void)
{
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("Free Surface width %d height %d.\r\n"), this->Width(), this->Height()));   
    m_pSurfHeap->Free();/*lint !e1551*/
    m_pSurfHeap = NULL;
}

/*****************************************************
 * Function: GetPhysicalAddress
 * Description: get physical address of surface
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: NONE
 * Output: NONE
 * Return: physical address of current surface
 * Others: NONE
 ****************************************************/
DWORD HisiSurf::GetPhysicalAddress(void)
{
    DWORD dwAddress;
    DWORD dwOffset;

    dwAddress = (DWORD)this->Buffer();
    dwOffset  = this->OffsetInVideoMemory();
    
#ifdef _CPPRTTI
    if ((dwAddress - dwOffset) == (dynamic_cast<HisiDisp *>(GetDDGPE()))->m_pSramBuffer)
#else
    if ((dwAddress - dwOffset) == ((HisiDisp *)GetDDGPE())->m_pSramBuffer)
#endif    
    {
        return gHisiArgs[MODEID].pSramBaseAddress + dwOffset - HISI_EDC_ES2_ES1_OFFSET;
    }
#ifdef _CPPRTTI
    else if ((dwAddress - dwOffset) == (dynamic_cast<HisiDisp *>(GetDDGPE()))->m_pSdramBuffer)
#else
    else if ((dwAddress - dwOffset) == ((HisiDisp *)GetDDGPE())->m_pSdramBuffer)
#endif 
    {
        return gHisiArgs[MODEID].pSdramBaseAddress + dwOffset;
    } 
    else 
    {
        DEBUGMSG(GPE_ZONE_HISI, (TEXT("Wrong Address.\n")));
    }
    return 0;
}

DWORD HisiSurf::GetGePhysicalAddress(void)
{
    DWORD dwAddress;
    DWORD dwOffset;

    dwAddress = (DWORD)this->Buffer();
    dwOffset  = this->OffsetInVideoMemory();
    
#ifdef _CPPRTTI
    if ((dwAddress - dwOffset) == (dynamic_cast<HisiDisp *>(GetDDGPE()))->m_pSramBuffer)
#else
    if ((dwAddress - dwOffset) == ((HisiDisp *)GetDDGPE())->m_pSramBuffer)
#endif    
    {
        return gHisiArgs[MODEID].pSramBaseAddress + dwOffset;
    }
#ifdef _CPPRTTI
    else if ((dwAddress - dwOffset) == (dynamic_cast<HisiDisp *>(GetDDGPE()))->m_pSdramBuffer)
#else
    else if ((dwAddress - dwOffset) == ((HisiDisp *)GetDDGPE())->m_pSdramBuffer)
#endif 
    {
        return gHisiArgs[MODEID].pSdramBaseAddress + dwOffset;
    } 
    else 
    {
        DEBUGMSG(GPE_ZONE_HISI, (TEXT("Wrong Ge Physical Address.\n")));
    }
    return 0;
}


